Skip to content

fix(charts): honour series opacity and dashArray on every series, not only a comparison one - #8159

Merged
os-justin merged 1 commit into
mainfrom
claude/issue-7698-series-opacity-dasharray
Sep 6, 2026
Merged

fix(charts): honour series opacity and dashArray on every series, not only a comparison one#8159
os-justin merged 1 commit into
mainfrom
claude/issue-7698-series-opacity-dasharray

Conversation

@os-justin

Copy link
Copy Markdown
Collaborator

Fixes #7698

@objectstack/spec declares ChartSeries.opacity ("Override series opacity") and ChartSeries.dashArray ("Override stroke dash pattern") as unconditional per-series overrides, and @object-ui/types' ChartDataSeriesSchema mirrors both. normalizeSeries read them off every series and the renderer then honoured them on a variant: 'comparison' overlay only — so an author who wrote { name: 'cost', opacity: 0.6 } on a primary series got a mark drawn exactly as if the key were absent. Option A per the card's adjudication: the renderer moves, not the declaration. Narrowing the published face to "comparison only" would be the renderer's tolerance dictating the contract, the direction AGENTS.md #0.1 forbids.

My own measurement — the card's body is wrong about where the defect lives, and the correction holds

Re-measured on origin/main @ c14d3a090 with the card's own census control rebuilt (grep -rniE 'opacity|dasharray' packages/plugin-charts/src, tests excluded). The card's body says all five cmp?.… call sites apply fillOpacity / strokeOpacity / strokeDasharray. They do not — and there are seven of them, not five (the body's list omits the two Line sites):

mark line on c14d3a090 what it actually passed
Scatter :1832 fillOpacity only
Line (combo) :1898 strokeOpacity, strokeDasharray
Area (combo) :1905 fillOpacity, strokeOpacity, strokeDasharray
Bar (combo) :1911 fillOpacity only
Bar :2037 fillOpacity only
Line :2048 strokeOpacity, strokeDasharray
Area :2056 fillOpacity, strokeOpacity, strokeDasharray

And comparisonStyle:96 was s.dashArray ?? (kind === 'line' || kind === 'area' ? '4 4' : undefined) — the ?? takes the left side whatever the kind, so the helper already returned an authored dash for bar and scatter too. Confirmed: what dropped it is the mark component, not the variant guard, and a fix aimed only at the guard would not have repaired dashArray at all.

The ablation below is the lit control for that claim, not the reading alone. Against the pre-fix implementation, the comparison-bar pin reports fillOpacity: '0.4' present and strokeDasharray: null — the muted default arrived, the authored dash did not. That is the mark-component half, isolated.

The fix — two halves, gated differently

comparisonStyle becomes seriesStyle and no longer returns null:

  • Authored opacity / dashArray apply whatever the variant.
  • The muted comparison DEFAULTS (lower opacity, the '4 4' line/area dash) stay gated on variant === 'comparison'.
  • Bar and Scatter marks now pass strokeOpacity and strokeDasharray through, so the authored dash is no longer dropped at the mark.

Existing comparison series are byte-for-byte unaffected. The authored branch already won over the defaults, and the two stroke defaults no mark ever consumed (bar 0.6, scatter 0.5 — this renderer strokes neither family) are now spelled undefined, so opening strokeOpacity on those marks hands them no default they never had. Pinned directly: a comparison bar carrying no keys keeps fill-opacity="0.4" and gains neither stroke-opacity nor stroke-dasharray.

A primary series carrying neither key is untouched — pinned as all three attributes absent.

Only a stroked mark can show a dash, and this renderer strokes Line and Area, so an authored dashArray on a bar or scatter reaches the mark and paints nothing. That is the mark's geometry, not a condition on the key, and the docs now say exactly that rather than describing it as a restriction.

Read-coupling to PR #7684 (binding, discharged)

#7684 landed and stated the comparison-only condition as an interim measure. That wording is now wrong and comes out in this same change, per objectui#7070:

  • packages/types/src/data-display.ts — the ChartDataSeries.opacity and .dashArray JSDoc. Comment-only: git diff -U0 on that file yields zero changed lines outside a block comment.
  • content/docs/plugins/plugin-charts.mdx — both series-table rows plus the paragraph under the area example. Prose only: the three changed lines are 193, 194 and 198, and the fences in that region are 162-179, 200-216, so no compiled snippet moved.

Scope held

packages/core/src/utils/chart-presentation.ts was not touched — its seriesPresentation already forwards both keys on the dataset path, so the dispatch's flagged out-of-plugin file stays out of this PR.

Filed separately rather than folded in: objectui#8157 — the radar mark maps over series but hard-codes fillOpacity={0.6} and never calls the helper, so opacity, dashArray and the whole comparison treatment are inert on a radar chart for every variant. Repairing it would newly mute existing comparison radar series (0.6 becomes the helper's 0.5), a visible change to already-drawn charts that wants its own decision. Not addressed here; it stays open.

Not touched here either, all separate cards in the same measurement family: objectui#7690, objectui#7694, objectui#7682, objectui#7546.

Verification

All runs on the final commit 5d68aecbb unless stated. Heavy runs went through the container's shared verify lock; wall-clock figures are shared-box seconds.

Tests

  • pnpm exec vitest run packages/plugin-charts/48 files, 447 tests passed.
  • pnpm exec vitest run packages/types/ packages/plugin-dashboard/ packages/plugin-report/ examples/schema-catalog/271 files, 5611 tests passed (the chart-rendering consumers).
  • New pin: packages/plugin-charts/src/ChartRenderer.seriesPresentation.test.tsx, 13 tests.

Reverse verification (ablation). Predicted direction: RED. The one file was restored to its c14d3a090 bytes, with the mutation proven on disk before the run — git hash-object of the working file equalled the pre-fix blob 63a5e34c9 and differed from the HEAD blob ae52b1d01; anchored counts moved seriesStyle 6 to 0 and comparisonStyle 0 to 6. Result: 8 of 13 failed, and the 5 that passed are exactly the regression pins (the comparison defaults, the untouched primary series, and an authored opacity overriding a comparison default — all of which held before this change and must keep holding). Restore leg proven by state, not by an exit code: git diff HEAD empty, git status clean, working blob back to ae52b1d01. The script carried an absolute-path trap ... EXIT INT TERM.

Type checking. pnpm --filter @object-ui/plugin-charts --filter @object-ui/types type-check — exit 0. This package's type-check is tsc --noEmit && tsc -p tsconfig.test.json, so the new test file is type-checked too rather than excluded.

Gates run locally (all exit 0, quoting each gate's own verdict line): check:control-bytes, check:vi-mock-specifiers, check:vi-mock-inherit, check:doc-fences, check:doc-types, check:doc-links, check:doc-expression-carriage, check:doc-example-readers, check:unreferenced-sources, check:spec-symbols, check:shell-escape-residue, check-changeset-presence, check-changeset-no-major, check-changeset-fixed, check-changeset-overwrite, and check-governed-queue-guard --test on all five changed paths (NOT GOVERNED, 5 of 5).

Two gates NOT MEASURED locally, left to CI — both exited on a stated precondition, neither is a finding:

  • check:doc-snippets — exit 2, PRECONDITION NOT MET: it needs 32 packages plus closures built, which does not fit this container's foreground budget under contention. It compiles documented TS blocks, and this diff changes none (see the fence arithmetic above).
  • check:eager-closure — exit 2, no apps/console/dist/eager-closure.json, so no ceiling to weigh. The diff adds no import, so the eager payload is unchanged.

Lint — a declared, measured narrowing. Repo-wide lint (turbo run lint, 40 packages each running eslint .) is CI's run. Locally, ESLint ran on the three changed source files: 3 files linted, 0 errors, 77 warnings, file count read from --format json output length. Every warning is pre-existing @typescript-eslint/no-explicit-any in AdvancedChartImpl.tsx; the diff adds no new any (the replaced helper already took s: any), and no --max-warnings is set anywhere in the lint pipeline — lint.yml says so in as many words. Invariance for untouched files: type-aware linting is not enabledeslint.config.js sets no parserOptions.project and no projectService (the only matches in the repo are two RuleTester fixtures under eslint-rules/), so every verdict is a per-file function of that file's own bytes, and this diff cannot move the verdict of a file it does not touch.

Changeset. .changeset/7698-series-opacity-dasharray-unconditional.md, @object-ui/plugin-charts: minor + @object-ui/types: patch, no major (AGENTS.md version alignment). Not a skip-changeset PR — this ships a user-visible behaviour change.


🤖 Generated with Claude Code

https://claude.ai/code/session_01YBWFb5YgMU5dw8p2VKj16S


Generated by Claude Code

`@objectstack/spec` declares `ChartSeries.opacity` and `ChartSeries.dashArray`
as unconditional per-series overrides. `normalizeSeries` read both off every
series and `comparisonStyle` then discarded them for anything but a
`variant: 'comparison'` overlay, so an authored key on a primary series drew
exactly like no key at all.

Two gaps, not one. The `variant` guard was the visible half; the second only
showed on `dashArray`, which `comparisonStyle` already returned for every
family while the Bar and Scatter marks passed `fillOpacity` only and dropped
`strokeDasharray` / `strokeOpacity` — broken on those families even for a
comparison series.

`comparisonStyle` becomes `seriesStyle`: the authored values apply whatever the
variant, the muted overlay DEFAULTS stay gated on `variant: 'comparison'`, and
Bar / Scatter now pass all three channels. The two stroke defaults no mark ever
consumed (bar, scatter — neither is stroked here) are spelled `undefined` so
opening those props hands them no default they never had; every value a
comparison series painted before is unchanged.

The `ChartDataSeries` mirror docs and the plugin-charts reference stated the
comparison-only condition as an interim measure; both are corrected here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YBWFb5YgMU5dw8p2VKj16S

Copy link
Copy Markdown
Collaborator Author

Contract review — PASS — PR #8159 (objectui#7698), head 5d68aecbb

Reviewed-by: domain:ui @ objectui PM seat, session_01YBWFb5YgMU5dw8p2VKj16S, in-seat at opus = TIER_DEFAULT. CONTRACT_REVIEW_TIER (claude-fable-5-1) is measured unavailable (429). ⛔ Not described as running at contract-review tier.

⭐ The Zone-2 clause worked: the correction I handed over was itself incomplete

My dispatch handed the dev comment 5550238143's mark-component table explicitly as the previous seat's reading, ⛔ not as fact, and told it to rebuild the census with its own lit control. It did — and found the correction short.

Re-measured by this seat on origin/main, cmp?. call sites in AdvancedChartImpl.tsx:

:1832  Scatter        fillOpacity only
:1898  Line  (combo)  strokeOpacity + strokeDasharray
:1905  Area  (combo)  all three
:1911  Bar   (combo)  fillOpacity only
:2037  Bar            fillOpacity only
:2048  Line           strokeOpacity + strokeDasharray
:2056  Area           all three

seven, not the card's five (with stale numbers) and not the correction's four. The correction omitted both Line sites and Area :1905. ⭐ Three successive readings of the same file, each closer; the one that held is the one taken with a control rather than inherited.

The mechanism claim also confirmed at :96: s.dashArray ?? (kind === 'line' || kind === 'area' ? '4 4' : undefined) — the ?? takes the left side whatever the kind, so an authored dash was returned for bar and scatter too and then dropped at the mark. ⭐ And the dev proved that with a lit control rather than a reading: against the pre-fix implementation the comparison-bar pin reports fillOpacity '0.4' present and strokeDasharray null — the two channels diverging at one call site is what makes "the mark owns the drop" a measurement instead of an inference.

① Derived judgments

Clause-②: NO, verified. The packages/types/src/data-display.ts diff is entirely inside JSDoc block commentsopacity?: number; and dashArray?: string; are byte-identical, and no spec or mirror member moves. Hence @object-ui/types: patch, which is the honest minimum for a comments-only change. @object-ui/plugin-charts: minor for the behaviour. ✅

Option A implemented as adjudicated, and both halves closed. comparisonStyleseriesStyle, no longer returning null off a comparison series, so an authored key applies whatever the variant; the muted defaults stay gated on variant === 'comparison'. And the Bar and Scatter marks now pass strokeOpacity / strokeDasharray, closing the half the card's body located in the wrong place.

⭐⭐ The sharpest thing in this PR, and it is a defect the fix could easily have introduced. The old helper computed strokeOpacity for bar (0.6) and scatter (0.5) — values no mark ever consumed, because this renderer strokes neither family. Opening strokeOpacity on those marks would therefore have handed them a default they never had, newly muting every comparison bar and scatter stroke. The dev spotted it and spelled those two undefined, then pinned exactly that:

「gives a comparison bar NO dash and NO stroke fade — the defaults are per family, and the marks that just gained these props must not inherit one」

opening a channel can leak a previously-inert default. That is not in the card, not in triage, and not in my dispatch. It is the kind of thing that ships as "a small visual regression nobody can explain".

② semver and read-coupling

minor + patch, major forbidden, Changeset Bump Policy green. ✅

The read-coupling my dispatch made binding is satisfied in BOTH places — PR #7684's interim "comparison-only" wording is removed from the plugin-charts.mdx table rows and from the ChartDataSeries mirror JSDoc. objectui#7070's rule (restated, ⛔ not left to rot) is met, and the replacement wording is more precise than a simple deletion: it distinguishes 「the key is unconditional」 from 「only a stroked mark can show a dash — the mark's geometry, not a condition on the key」. ⭐ That asymmetry is real and would have been easy to paper over.

③ Boundary flags

  • The pins render through ChartRenderer and read the DOM, ⛔ not seriesStyle directly — with the reason stated: 「the defect was a value surviving normalization and then dying at the mark: only the DOM says whether the mark applied it」. ⭐ A unit test on the helper would have passed against the broken tree.
  • paint() treats null — the DOM's answer for an absent attribute — as a real reading, and several pins assert exactly that. That is what lets "no default leaked" be asserted rather than assumed.
  • One pin names the second gap explicitly: 「reaches a COMPARISON bar mark (a fix at the variant guard alone would not)」. It is the case that fails for a different reason than the primary-series cases, and it is pinned separately for that reason.
  • Ablation: 8 of 13 failed, and the 5 that passed are exactly the regression pins. Mutation proven on disk before the run — working blob equal to the pre-fix blob 63a5e34c9 and different from HEAD's ae52b1d01, with anchored counts moving seriesStyle 6→0 and comparisonStyle 0→6. Restore proven by state: git diff HEAD empty, git status clean, blob back to ae52b1d01.
  • The stale-dist hazard addressed by argument: the pin imports ./ChartRenderer and ./AdvancedChartImpl relatively and the root vitest config aliases every workspace specifier to src, so the mutated source is the resolved module.
  • packages/core/src/utils/chart-presentation.ts untouchedseriesPresentation already forwards both keys, so the dispatch's "say so explicitly if you touch it" clause resolved to not needed.
  • Two gates NOT MEASURED with stated preconditions, and the first carries a specific argument rather than a shrug: check:doc-snippets compiles documented TS blocks, the three changed .mdx lines are 193/194/198, and the fences in that region are 162-179 and 200-216 ⇒ this diff changes no compiled block. check:eager-closure has no apps/console/dist/eager-closure.json to weigh and the diff adds no import. ✅
  • Lint narrowing carries all three legs, including the invariance argument (no parserOptions.project / projectService; the only repo matches are two RuleTester fixtures).

⭐ Out-of-scope finding declined for a measured reason, not a scope reflex. objectui#8157 — the radar mark hard-codes fillOpacity={0.6} and never calls the presentation helper, so authored opacity, dashArray and the whole comparison treatment are inert on radar for every variant. It was ⛔ not folded in because repairing it would newly mute existing comparison radar series (0.6 → the helper's non-bar/non-area default 0.5) — a visible change to already-drawn charts that wants its own decision. ⇒ declining because the fix has an unbudgeted visible consequence is a better reason than "out of scope", and it is the same care that produced the bar/scatter default fix above.

Verdict

PASS. No Clause-② carrier is owed. ⛔ Not landing yet — CI has just started: 32 enumerated against total_count: 32, 10 in_progress (Lint, Test shards 1–4, Type Check, Build Docs, Bundle Analysis, README Export Check, Doc Snippet Type Check, Skill Example Check, Live E2E), zero failures. ⚠️ Lint is unread and this seat will ⛔ not flip ready without it. Live E2E will fail; its signature will be matched against objectstack#16186's before it is stood down.


Generated by Claude Code

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3187.7 KB 3191.4 KB
Main entry chunk (gzip) 143.6 KB 350 KB
Entry file index-CCCrd7KN.js
Status PASS

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 15.67KB 5.75KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 5.13KB 2.35KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 498.09KB 113.98KB
core (index.js) 6.96KB 2.79KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 182.08KB 50.62KB
fields (index.js) 243.04KB 61.36KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 6.57KB 2.76KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.84KB 10.94KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 11.71KB 4.29KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 5.12KB 1.74KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 15.16KB 3.68KB
plugin-calendar (index.js) 47.29KB 13.18KB
plugin-charts (index.js) 70.62KB 19.71KB
plugin-chatbot (index.js) 193.54KB 46.04KB
plugin-dashboard (index.js) 131.41KB 34.43KB
plugin-designer (index.js) 211.51KB 43.01KB
plugin-detail (index.js) 247.75KB 63.50KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 131.01KB 32.32KB
plugin-gantt (index.js) 167.16KB 40.99KB
plugin-grid (index.js) 208.58KB 56.63KB
plugin-kanban (index.js) 52.46KB 14.57KB
plugin-list (index.js) 113.34KB 27.72KB
plugin-map (index.js) 20.49KB 6.83KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.42KB 11.92KB
plugin-timeline (index.js) 30.10KB 8.74KB
plugin-tree (index.js) 9.33KB 3.25KB
plugin-view (index.js) 84.48KB 20.81KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 81.07KB 26.86KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.55KB 2.45KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 13.64KB 4.59KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.74KB 1.41KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@os-justin
os-justin marked this pull request as ready for review September 6, 2026 22:00
@os-justin
os-justin added this pull request to the merge queue Sep 6, 2026
Merged via the queue into main with commit 967e5d8 Sep 6, 2026
33 of 34 checks passed
@os-justin
os-justin deleted the claude/issue-7698-series-opacity-dasharray branch September 6, 2026 22:16
baozhoutao pushed a commit that referenced this pull request Sep 6, 2026
…27-plugin-ai

Keeps the batch-27 work on a head that carries #8159. The merged commit
touches packages/plugin-charts, packages/types/src/data-display.ts and
content/docs/plugins/plugin-charts.mdx -- disjoint from this branch's
file surface (packages/plugin-ai/README.md, scripts/check-doc-snippet-types.mjs),
so every gate reading in the PR body is pinned to the merged head.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants